package com.drg.center.dao;

import cn.hutool.core.util.ArrayUtil;
import com.alibaba.fastjson.JSONObject;
import com.drg.center.entity.PatientCaseEsPO;
import com.drg.center.entity.result.*;
import com.drg.center.mapper.PatientCaseEsMapper;
import com.google.common.collect.Lists;
import com.guaike.core.entity.exception.ApiException;
import com.guaike.core.utils.BigDecimalUtil;
import com.guaike.core.utils.CompareUtil;
import com.guaike.core.utils.LocalDateUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.BucketOrder;
import org.elasticsearch.search.aggregations.bucket.filter.FilterAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.filter.ParsedFilter;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
import org.elasticsearch.search.aggregations.bucket.histogram.Histogram;
import org.elasticsearch.search.aggregations.bucket.nested.ParsedNested;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.metrics.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Repository;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.List;

import static org.elasticsearch.index.query.QueryBuilders.boolQuery;

/**
 * ES科室维度聚合统计
 *
 * @Author: zhangxilin
 * @Date: 2024/12/8
 */
@Slf4j
@Repository
public class EsDepartAngleDAO {

    @Autowired
    private PatientCaseEsMapper patientCaseEsMapper;

    @Autowired
    private ElasticsearchOperations elasticsearchOperations;

    /**
     * 科室盈亏分析
     * DSL-010
     *
     * @param departCode
     * @param startDate
     * @param endDate
     * @return
     */
    public List<DepartProfitLossPageVO> getDepartProfitLossList(String departCode, LocalDate startDate, LocalDate endDate) {
        // 检索条件
        BoolQueryBuilder queryBuilder = boolQuery();
        queryBuilder.must(QueryBuilders.termQuery("hasOut", true));
        if (StringUtils.isNotBlank(departCode)) {
            queryBuilder.must(QueryBuilders.termQuery("outDepartCode", departCode));
        }
        if (startDate != null) {
            queryBuilder.must(QueryBuilders.rangeQuery("outHospitalDate").gte(LocalDateUtil.getTimestamp(startDate)));
        }
        if (endDate != null) {
            queryBuilder.must(QueryBuilders.rangeQuery("outHospitalDate").lt(LocalDateUtil.getTimestamp(endDate.plusDays(1))));
        }


        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(queryBuilder)
                .addAggregation(AggregationBuilders.terms("departments")
                        .field("outDepartCode")
                        .size(10000)
                        .order(BucketOrder.aggregation("total_profit", false))
                        .subAggregation(AggregationBuilders.sum("total_profit").field("profit").format("0.00"))
                        .subAggregation(AggregationBuilders.count("caseCount").field("caseCode"))
                        .subAggregation(AggregationBuilders.filter("caseInDrgCount",
                                QueryBuilders.boolQuery()
                                        .must(QueryBuilders.existsQuery("drgCode"))
                                        .mustNot(QueryBuilders.termQuery("drgCode", "0000"))
                                ).subAggregation(AggregationBuilders.count("count").field("caseCode"))
                        )
//                        .subAggregation(new FilterAggregationBuilder("caseInDrgCount",
//                                QueryBuilders.existsQuery("drgCode"))
//                                .subAggregation(AggregationBuilders.count("count").field("caseCode"))
//                        )
                        .subAggregation(AggregationBuilders.cardinality("drgCount").field("drgCode"))
                        .subAggregation(AggregationBuilders.terms("most_overbudget_doctor")
                                .field("doctorCode")
                                .size(1)
                                .order(BucketOrder.aggregation("overExpectCost_sum", false))
                                .subAggregation(AggregationBuilders.sum("overExpectCost_sum").field("overExpectCost").format("0.00"))
                                .subAggregation(AggregationBuilders.topHits("doctorName")
                                        .size(1)
                                        .fetchSource(new String[]{"doctorName"}, null)))
                        .subAggregation(AggregationBuilders.terms("most_overbudget_drg")
                                .field("drgCode")
                                .size(1)
                                .order(BucketOrder.aggregation("overExpectCost_sum", false))
                                .subAggregation(AggregationBuilders.sum("overExpectCost_sum").field("overExpectCost").format("0.00"))
                                .subAggregation(AggregationBuilders.topHits("drgName")
                                        .size(1)
                                        .fetchSource(new String[]{"drgName"}, null)))
                        .subAggregation(AggregationBuilders.topHits("departName")
                                .size(1)
                                .fetchSource(new String[]{"outDepartName"}, null)))
                .withPageable(PageRequest.of(0, 1))
                .build();

        Aggregations aggregations = elasticsearchOperations.search(searchQuery, PatientCaseEsPO.class).getAggregations();

        Terms departments = (ParsedStringTerms) aggregations.get("departments");

        List<DepartProfitLossPageVO> results = new ArrayList<>();
        for (Terms.Bucket bucket : departments.getBuckets()) {
            DepartProfitLossPageVO vo = new DepartProfitLossPageVO();

            //科室编号
            vo.setDepartCode(bucket.getKeyAsString());
            //科室名称
            TopHits departNameHits = (TopHits) bucket.getAggregations().get("departName");
            if (!ArrayUtil.isEmpty(departNameHits.getHits().getHits())) {
                vo.setDepartName((String) departNameHits.getHits().getHits()[0].getSourceAsMap().get("outDepartName"));
            }

            // 净盈亏金额
            ParsedSum totalProfitSum = bucket.getAggregations().get("total_profit");
            vo.setNetProfitLoss(BigDecimalUtil.parseBigDecimal(totalProfitSum.getValueAsString()));

            //病例数
            ValueCount caseCount = bucket.getAggregations().get("caseCount");
            vo.setCaseCount(Integer.parseInt(caseCount.getValue() + ""));

            //入组病例数
            Long caseInDrgCount = ((ParsedValueCount) ((ParsedFilter) bucket.getAggregations().get("caseInDrgCount")).getAggregations().get("count")).getValue();
            vo.setGroupCaseCount(Integer.parseInt(caseInDrgCount + ""));

            //DRG组数
            Long drgGroupCount = ((ParsedCardinality) bucket.getAggregations().get("drgCount")).getValue();
            vo.setDrgGroupCount(Integer.parseInt(drgGroupCount + ""));

            // 解析超支最多医生
            ParsedStringTerms mostOverbudgetDoctor = (ParsedStringTerms) bucket.getAggregations().get("most_overbudget_doctor");
            if (!mostOverbudgetDoctor.getBuckets().isEmpty()) {
                Terms.Bucket doctorBucket = mostOverbudgetDoctor.getBuckets().get(0);
                ParsedSum doctorOverSum = doctorBucket.getAggregations().get("overExpectCost_sum");
                vo.setDoctorOverExpectCost(BigDecimalUtil.parseBigDecimal(doctorOverSum.getValueAsString()));
                TopHits doctorNameHits = (TopHits) doctorBucket.getAggregations().get("doctorName");
                if (!ArrayUtil.isEmpty(doctorNameHits.getHits().getHits())) {
                    vo.setDoctorName((String) doctorNameHits.getHits().getHits()[0].getSourceAsMap().get("doctorName"));
                }
            }

            // 解析超支最多病组
            ParsedStringTerms mostOverbudgetDrg = (ParsedStringTerms) bucket.getAggregations().get("most_overbudget_drg");
            if (!mostOverbudgetDrg.getBuckets().isEmpty()) {
                Terms.Bucket drgBucket = mostOverbudgetDrg.getBuckets().get(0);
                ParsedSum drgOverSum = drgBucket.getAggregations().get("overExpectCost_sum");
                vo.setDrgOverExpectCost(BigDecimalUtil.parseBigDecimal(drgOverSum.getValueAsString()));
                TopHits drgNameHits = (TopHits) drgBucket.getAggregations().get("drgName");
                if (!ArrayUtil.isEmpty(drgNameHits.getHits().getHits())) {
                    vo.setDrgName((String) drgNameHits.getHits().getHits()[0].getSourceAsMap().get("drgName"));
                }
            }
            vo.setGroupRatio(BigDecimalUtil.calculatePercentage(vo.getGroupCaseCount(), vo.getCaseCount()) + "");
            vo.setCaseAverageProfitLoss(BigDecimal.ZERO);
            if (vo.getCaseCount() != null && vo.getCaseCount() != 0) {
                vo.setCaseAverageProfitLoss(BigDecimalUtil.calculatePercentage(vo.getNetProfitLoss(), new BigDecimal(vo.getCaseCount() + "")));
            }

            results.add(vo);
        }
        log.info("【EsDepartAngleDAO.getDepartProfitLossList】 list: {}", JSONObject.toJSONString(results));
        return results;
    }

    /**
     * 科室费用分析
     * DSL-012
     *
     * @param departCode
     * @param startDate
     * @param endDate
     * @return
     */
    public List<DepartAngleSttVO> getDepartCostSttList(String departCode, LocalDate startDate, LocalDate endDate) {
        // 检索条件
        BoolQueryBuilder queryBuilder = boolQuery();
        queryBuilder.must(QueryBuilders.termQuery("hasOut", true));
        if (StringUtils.isNotBlank(departCode)) {
            queryBuilder.must(QueryBuilders.termQuery("outDepartCode", departCode));
        }
        if (startDate != null) {
            queryBuilder.must(QueryBuilders.rangeQuery("outHospitalDate").gte(LocalDateUtil.getTimestamp(startDate)));
        }
        if (endDate != null) {
            queryBuilder.must(QueryBuilders.rangeQuery("outHospitalDate").lt(LocalDateUtil.getTimestamp(endDate.plusDays(1))));
        }

        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(queryBuilder)
                .addAggregation(AggregationBuilders.terms("deptAgg")
                        .field("outDepartCode")
                        .size(10000)
                        .order(BucketOrder.aggregation("totalCost", false))
                        .subAggregation(AggregationBuilders.sum("totalCost").field("totalCost").format("0.00"))
                        .subAggregation(AggregationBuilders.count("caseCount").field("caseCode"))
                        .subAggregation(AggregationBuilders.sum("total_profit").field("profit").format("0.00"))
                        .subAggregation(AggregationBuilders.sum("expectProfit").field("expectProfit").format("0.00"))
                        .subAggregation(AggregationBuilders.sum("inpatientDays").field("inpatientDays"))
                        .subAggregation(AggregationBuilders.sum("medicine_cost").field("medicineCost").format("0.00"))
                        .subAggregation(AggregationBuilders.sum("consumables_cost").field("consumablesCost").format("0.00"))
                        .subAggregation(AggregationBuilders.terms("treatClass_counts").field("treatClass").size(4))
                        .subAggregation(AggregationBuilders.terms("hasOperation_counts").field("hasOperation").size(2))
                        .subAggregation(AggregationBuilders.nested("operation_level_counts", "operationVOS")
                                .subAggregation(AggregationBuilders.count("opt_count").field("operationVOS.operationLevel"))
                                .subAggregation(AggregationBuilders.filter("level_3_cases", QueryBuilders.termQuery("operationVOS.operationLevel", "3"))
                                        .subAggregation(AggregationBuilders.count("leve3_count").field("operationVOS.operationLevel"))
                                )
                                .subAggregation(AggregationBuilders.filter("level_4_cases", QueryBuilders.termQuery("operationVOS.operationLevel", "4"))
                                        .subAggregation(AggregationBuilders.count("level_4_count").field("operationVOS.operationLevel"))
                                )
                        )
                        .subAggregation(AggregationBuilders.terms("drg_group").field("drgCode").size(100000)
                                .subAggregation(AggregationBuilders.count("cases_in_drg").field("caseCode")))
                        .subAggregation(AggregationBuilders.topHits("departName").size(1)
                                .fetchSource(new String[]{"outDepartName"}, null))
                )
                .withPageable(PageRequest.of(0, 1))
                .build();

        Aggregations aggregations = elasticsearchOperations.search(searchQuery, PatientCaseEsPO.class).getAggregations();
        Terms deptAgg = (ParsedStringTerms) aggregations.get("deptAgg");

        List<DepartAngleSttVO> list = Lists.newArrayList();
        for (Terms.Bucket bucket : deptAgg.getBuckets()) {
            DepartAngleSttVO vo = new DepartAngleSttVO();

            //科室编号
            vo.setDepartCode(bucket.getKeyAsString());

            //科室名称
            TopHits departNameHits = (TopHits) bucket.getAggregations().get("departName");
            if (!ArrayUtil.isEmpty(departNameHits.getHits().getHits())) {
                vo.setDepartName((String) departNameHits.getHits().getHits()[0].getSourceAsMap().get("outDepartName"));
            }

            //医疗总费用
            ParsedSum totalCostSum = bucket.getAggregations().get("totalCost");
            vo.setTotalCost(BigDecimalUtil.parseBigDecimal(totalCostSum.getValueAsString()));

            //病例数
            ValueCount caseCount = bucket.getAggregations().get("caseCount");
            vo.setCaseCount(Integer.parseInt(caseCount.getValue() + ""));

            // 净盈亏金额
            ParsedSum totalProfitSum = bucket.getAggregations().get("total_profit");
            vo.setProfit(BigDecimalUtil.parseBigDecimal(totalProfitSum.getValueAsString()));

            // 预测盈亏金额
            ParsedSum expectProfitSum = bucket.getAggregations().get("expectProfit");
            vo.setExpectProfit(BigDecimalUtil.parseBigDecimal(expectProfitSum.getValueAsString()));

            //住院总天数
            ParsedSum inpatientDaysSum = bucket.getAggregations().get("inpatientDays");
            vo.setInpatientDays((int) inpatientDaysSum.getValue());


            //药品费用
            ParsedSum medicineCostSum = bucket.getAggregations().get("medicine_cost");
            vo.setMedicineCost(BigDecimalUtil.parseBigDecimal(medicineCostSum.getValueAsString()));

            // 耗材费用
            ParsedSum consumablesCostSum = bucket.getAggregations().get("consumables_cost");
            vo.setConsumablesCost(BigDecimalUtil.parseBigDecimal(consumablesCostSum.getValueAsString()));

            //非药物中医疗法次数
            Terms treatClass_counts = (Terms) bucket.getAggregations().get("treatClass_counts");
            for (Terms.Bucket treatClassBucket : treatClass_counts.getBuckets()) {
                if (CompareUtil.isEqual(treatClassBucket.getKeyAsString(), "2.1")) {
                    vo.setTraditionalCount(Integer.parseInt(treatClassBucket.getDocCount() + ""));
                }
            }

            //手术病例数
            Terms hasOperationTerms = (Terms) bucket.getAggregations().get("hasOperation_counts");
            for (Terms.Bucket hasOperationBucket : hasOperationTerms.getBuckets()) {
                if (CompareUtil.isEqual(Integer.parseInt(hasOperationBucket.getKey() + ""), 1)) {
                    vo.setOperationCaseCount(Integer.parseInt(hasOperationBucket.getDocCount() + ""));
                }
            }


            //手术信息
            ParsedNested operationLevelCounts = bucket.getAggregations().get("operation_level_counts");
            ValueCount optCount = operationLevelCounts.getAggregations().get("opt_count");
            ParsedFilter level3CasesFilter = operationLevelCounts.getAggregations().get("level_3_cases");
            ParsedFilter level4CasesFilter = operationLevelCounts.getAggregations().get("level_4_cases");

            ValueCount leve3_count = level3CasesFilter.getAggregations().get("leve3_count");
            ValueCount leve4_count = level4CasesFilter.getAggregations().get("level_4_count");

            vo.setOperationCount(Integer.parseInt(optCount.getValue() + ""));

            vo.setOperationLevelThreeOrFourCount((int) (leve3_count.getValue() + leve4_count.getValue()));

            ParsedStringTerms drgGroup = bucket.getAggregations().get("drg_group");
            List<DrgAngleSttVO> drgAngleSttVOS = Lists.newArrayList();
            drgGroup.getBuckets().forEach(drgBucket -> {
                DrgAngleSttVO drgAngleSttVO = new DrgAngleSttVO();
                drgAngleSttVO.setDrgCode(((Terms.Bucket) drgBucket).getKeyAsString());
                ValueCount cases_in_drg_count = ((Terms.Bucket) drgBucket).getAggregations().get("cases_in_drg");
                drgAngleSttVO.setCaseCount(Integer.parseInt(cases_in_drg_count.getValue() + ""));
                drgAngleSttVOS.add(drgAngleSttVO);
            });

            vo.setDrgStt(drgAngleSttVOS);
            list.add(vo);

        }

        log.info("【EsDepartAngleDAO.getDepartCostSttList】size:{},  list: {}", list.size(), JSONObject.toJSONString(list.size() > 2 ? list.subList(0, 2) : list));
        return list;

    }

    /**
     * 病组盈亏分析
     * DSL-011
     *
     * @param departCode
     * @param drgCode
     * @param startDate
     * @param endDate
     * @return
     */
    public List<DrgAngleSttVO> getDrgProfitLossList(String departCode, String drgCode, LocalDate startDate, LocalDate endDate) {
        log.info(">>>>getDrgProfitLossList, param -> departCode:{}, drgCode: {}, startDate: {}, endDate: {}", departCode, drgCode, startDate, endDate);
        // 检索条件
        BoolQueryBuilder queryBuilder = boolQuery();
        queryBuilder.must(QueryBuilders.termQuery("hasOut", true));
        if (StringUtils.isNotBlank(departCode)) {
            queryBuilder.must(QueryBuilders.termQuery("outDepartCode", departCode));
        }
        if (StringUtils.isNotBlank(drgCode)) {
            queryBuilder.must(QueryBuilders.termQuery("drgCode", drgCode));
        }
        if (startDate != null) {
            queryBuilder.must(QueryBuilders.rangeQuery("outHospitalDate").gte(LocalDateUtil.getTimestamp(startDate)));
        }
        if (endDate != null) {
            queryBuilder.must(QueryBuilders.rangeQuery("outHospitalDate").lt(LocalDateUtil.getTimestamp(endDate.plusDays(1))));
        }

        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(queryBuilder)
                .addAggregation(AggregationBuilders.terms("drgAgg")
                        .field("drgCode")
                        .size(20000)
                        .order(BucketOrder.aggregation("total_profit", false))
                        .subAggregation(AggregationBuilders.sum("total_profit").field("profit").format("0.00"))
                        .subAggregation(AggregationBuilders.count("caseCount").field("caseCode"))
                        .subAggregation(AggregationBuilders.sum("totalCost").field("totalCost").format("0.00"))
                        .subAggregation(AggregationBuilders.sum("inpatientDays").field("inpatientDays"))
                        .subAggregation(AggregationBuilders.filter("dealthCount", QueryBuilders.termQuery("outType", "4"))
                                .subAggregation(AggregationBuilders.count("caseCount").field("caseCode"))
                        )
                        .subAggregation(AggregationBuilders.terms("loss_by_depart")
                                .field("outDepartCode")
                                .size(1)
                                .order(BucketOrder.aggregation("profit_sum", true))
                                .subAggregation(AggregationBuilders.sum("profit_sum").field("profit").format("0.00"))
                                .subAggregation(AggregationBuilders.topHits("departName")
                                        .size(1)
                                        .fetchSource(new String[]{"outDepartName"}, null)))
                        .subAggregation(AggregationBuilders.topHits("drgName")
                                .size(1)
                                .fetchSource(new String[]{"drgName"}, null)))
                .withPageable(PageRequest.of(0, 1))
                .build();

        Aggregations aggregations = elasticsearchOperations.search(searchQuery, PatientCaseEsPO.class).getAggregations();
        Terms departments = (ParsedStringTerms) aggregations.get("drgAgg");

        List<DrgAngleSttVO> list = Lists.newArrayList();
        for (Terms.Bucket bucket : departments.getBuckets()) {
            DrgAngleSttVO vo = new DrgAngleSttVO();

            //DRG编码
            vo.setDrgCode(bucket.getKeyAsString());

            //DRG名称
            TopHits drgNameHits = (TopHits) bucket.getAggregations().get("drgName");
            if (!ArrayUtil.isEmpty(drgNameHits.getHits().getHits())) {
                vo.setDrgName((String) drgNameHits.getHits().getHits()[0].getSourceAsMap().get("drgName"));
            }

            // 净盈亏金额
            ParsedSum totalProfitSum = bucket.getAggregations().get("total_profit");
            vo.setProfit(BigDecimalUtil.parseBigDecimal(totalProfitSum.getValueAsString()));

            //病例数
            ValueCount caseCount = bucket.getAggregations().get("caseCount");
            vo.setCaseCount(Integer.parseInt(caseCount.getValue() + ""));

            //住院总天数
            ParsedSum inpatientDaysSum = bucket.getAggregations().get("inpatientDays");
            vo.setInpatientDays((int) inpatientDaysSum.getValue());

            //死亡病例数
            ParsedFilter dealthCountFilter = bucket.getAggregations().get("dealthCount");
            ValueCount dealthCount = dealthCountFilter.getAggregations().get("caseCount");
            vo.setDealthCase((int) dealthCount.getValue());

            // 医疗总费用
            ParsedSum totalCostSum = bucket.getAggregations().get("totalCost");
            vo.setTotalCost(BigDecimalUtil.parseBigDecimal(totalCostSum.getValueAsString()));


            // 解析亏损最多科室
            ParsedStringTerms lossByDepartTerms = (ParsedStringTerms) bucket.getAggregations().get("loss_by_depart");
            if (!lossByDepartTerms.getBuckets().isEmpty()) {
                Terms.Bucket lossDeptBucket = lossByDepartTerms.getBuckets().get(0);
                ParsedSum lossDeptSum = lossDeptBucket.getAggregations().get("profit_sum");
                vo.setLossMostDepartCost(BigDecimalUtil.parseBigDecimal(lossDeptSum.getValueAsString()));
                TopHits departNameHits = (TopHits) lossDeptBucket.getAggregations().get("departName");
                if (!ArrayUtil.isEmpty(departNameHits.getHits().getHits())) {
                    vo.setLossMostDepartName((String) departNameHits.getHits().getHits()[0].getSourceAsMap().get("departName"));
                }
            }
            list.add(vo);
        }

        log.info("【EsDepartAngleDAO.getDrgProfitLossList】size:{},  list: {}", list.size(), JSONObject.toJSONString(list.size() > 2 ? list.subList(0, 2) : list));
        return list;
    }

    /**
     * 科室例均费用分布(DSL-121)
     *
     * @param year
     * @param departCodeList
     * @return
     */
    public ChartLineVO getDepartAvgCostTrend(Integer year, List<String> departCodeList) {
        if (year == null) {
            throw new ApiException("请选择年份");
        }

        // 检索条件
        BoolQueryBuilder queryBuilder = boolQuery();
        queryBuilder.must(QueryBuilders.termQuery("hasOut", true));


        LocalDateTime firstDayOfYear = LocalDateUtil.getFirstDayOfYear(year);
        LocalDateTime lastDayOfYear = LocalDateUtil.getLastDayOfYear(year);
        queryBuilder.must(QueryBuilders.rangeQuery("outHospitalDate").gte(LocalDateUtil.getTimestamp(firstDayOfYear)));
        queryBuilder.must(QueryBuilders.rangeQuery("outHospitalDate").lte(LocalDateUtil.getTimestamp(lastDayOfYear)));


        if (!CollectionUtils.isEmpty(departCodeList)) {
            queryBuilder.must(QueryBuilders.termsQuery("outDepartCode", departCodeList));
        }


        DateHistogramAggregationBuilder dateHistogramAgg = AggregationBuilders.dateHistogram("monthly_profit")
                .field("outHospitalDate")
                .calendarInterval(DateHistogramInterval.MONTH)
                .format("yyyy-MM")
                .timeZone(ZoneId.of("+08:00"))
                .subAggregation(AggregationBuilders.avg("medicineCost").field("medicineCost").format("0.00"))
                .subAggregation(AggregationBuilders.avg("consumablesCost").field("consumablesCost").format("0.00"))
                .subAggregation(AggregationBuilders.avg("otherCost").field("otherCost").format("0.00"));


        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(queryBuilder)
                .addAggregation(dateHistogramAgg)
                .withPageable(PageRequest.of(0, 1))
                .build();

        Aggregations aggregations = elasticsearchOperations.search(searchQuery, PatientCaseEsPO.class).getAggregations();
        Histogram perMonthAgg = aggregations.get("monthly_profit");


        List<ChartLineSeriesVO> series = Lists.newArrayList();

        List<String> monthList = Lists.newArrayList();
        List<Object> medicineCostList = Lists.newArrayList();
        List<Object> consumablesCostList = Lists.newArrayList();
        List<Object> otherCostList = Lists.newArrayList();


        List<? extends Histogram.Bucket> buckets = perMonthAgg.getBuckets();
        for (Histogram.Bucket bucket : buckets) {
            String month = bucket.getKeyAsString();
            monthList.add(month);
            ParsedAvg medicineCostAvg = bucket.getAggregations().get("medicineCost");
            ParsedAvg consumablesCostAvg = bucket.getAggregations().get("consumablesCost");
            ParsedAvg otherCostAvg = bucket.getAggregations().get("otherCost");

            BigDecimal medicineCost = BigDecimalUtil.parseBigDecimal(medicineCostAvg.getValueAsString());
            BigDecimal consumablesCost = BigDecimalUtil.parseBigDecimal(consumablesCostAvg.getValueAsString());
            String otherCostStr = otherCostAvg.getValueAsString();
            if (CompareUtil.isEqual("Infinity", otherCostStr)) {
                otherCostStr = null;
            }

            BigDecimal otherCost = BigDecimalUtil.parseBigDecimal(otherCostStr);

            medicineCostList.add(medicineCost == null ? BigDecimal.ZERO : medicineCost);
            consumablesCostList.add(consumablesCost == null ? BigDecimal.ZERO : consumablesCost);
            otherCostList.add(otherCost == null ? BigDecimal.ZERO : otherCost);
        }
        series.add(new ChartLineSeriesVO("次均药品费用", medicineCostList));
        series.add(new ChartLineSeriesVO("次均耗材费用", consumablesCostList));
        series.add(new ChartLineSeriesVO("次均其他费用", otherCostList));

        ChartLineVO vo = new ChartLineVO();
        vo.setDataX(monthList);
        vo.setSeries(series);
        log.info("【EsDrgAngleDAO.getDrgAvgCostTrend】 vo: {}", JSONObject.toJSONString(vo));
        return vo;
    }


}
